import socket
import sys
import os
import math

#class Weapon:
#    def __init__(self, t, ad, sd):
#        self.type = t
#        self.armor_damage = ad
#        self.shield_damage = sd

class UnitDB:
    """Database to store and manage units."""
    def __init__(self):
        """Initializes an empty database."""
        self.units = list()
        self.msg_queue = list()
        self.it = 0 # iterator used to track communications frames
        self.del_queue = []

    def queue(self, msg):
        """Adds message to queue."""
        self.msg_queue.append(msg)

    def tick(self):
        """Parses messages scheduled for the current iteration and updates
        units."""
        while True:
            msg = self._next_msg()
            if not msg:
                break
            self._lookup_msg(msg)
        self._update_units()
        self.it += 1

    def combat_tick(self, weapon_db):
        for unit in self.units:
            unit.combat_tick(weapon_db, self)

    def _add_unit(self, msg):
        """Adds the specified unit to the database."""
        self.units.append(Unit(msg[3], msg[4]))

    def _attack(self, msg):
        self.units[msg[3]].attack(self.units[msg[4]])

    def _del_unit(self, msg):
        """Deletes the specified unit from the database."""
        pass

    def _move_unit(self, msg):
        """Sends a move command to the specified unit."""
        self.units[msg[3]].move_target = msg[4]
        self.units[msg[3]].target = 0

    def _lookup_msg(self, msg):
        """Calls the function mapped to the key given in the provided message."""
        msg_lu = {"add": self._add_unit, "attack": self._attack, "move": self._move_unit}
        try:
            msg_lu[msg[2]](msg)
        except KeyError:
            print "Warning: Key", self.msg[1], "in message", \
                self.msg, "not recognized."

    def _next_msg(self):
        """Returns the next message from self.msg_queue that needs to be
        executed during the current iteration. Returns False if there are no
        remaining messages."""
        if self.msg_queue and self.msg_queue[0][0] == self.it:
            return self.msg_queue.pop(0)
        return False

    def _update_units(self):
        """Calls Unit.tick() on all units in the database."""
        while len(self.del_queue)>0:
            unit = self.del_queue.pop()
            print "deleting",unit
            unit.atdeath(self.units)
            self.units.remove(unit)#self.del_queue.pop())
        for u in self.units:
            if u.tick() == 1:
                print "queueing",u
                self.del_queue.append(u)


class Unit:
    """Unit class

    Used directly by Server, inherited by UIUnit to be used by UIClient.
    """
    def __init__(self, t, p):
        """Creates a unit of type t at position p."""
        self.type = t
        self.move_target = self.pos = p
        self.vel = 5 # for testing, vel = max distance travelled in time step
        self.health = 50
        self.damage = 0
        self.sdamage = 0
        self.shield = 50
        self.hitbox = list()
        self.target = 0

    def tick(self):
        """Advances unit simulation one step."""
        self.move()
        if (self.sdamage > 0) and (self.shield > 0):
            self.shield -= self.sdamage
            print "Shields to",self.shield
        elif (self.sdamage == 0) and (self.shield < 50):
            self.shield += 5
            print "Shields to",self.shield
        if (self.damage > 0) and (self.shield < 1):
            self.health -= self.damage
            print "Health to",self.health
        self.damage = 0
        self.sdamage = 0
        if self.health < 1:
            print "death"
            return 1
        else :
            return 0

    def combat_tick(self, weapon_db, unit_db):
        """
        Called each combat tick, which happen at X times the rate of
        communication ticks, this will spawn any bullets needed
        """
        #this will be changed to be based on specific unit for fire rate
        #currently will spawn bullet every combat tick
        if (self.target != 0):
            self._spawn(weapon_db)

    def attack(self, target):
        #this will need some error checking for target validity
        #for now assume decent programmers working on project
        self.target = target

    def hit(self, weapon):
        """
        take hit from weapon, called by attacker
        """
        self.damage += weapon.armor_damage
        self.sdamage += weapon.shield_damage

    def move(self):
        """Moves unit one step towards its destination."""
        if self.move_target != self.pos:
            x1, y1 = self.move_target[0], self.move_target[1]
            x2, y2 = self.pos[0], self.pos[1]
            d = math.sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1))
            if d < self.vel:
                self.pos = self.move_target
            else:
                self.pos = ((x1 - x2)/d*self.vel+x2, (y1 - y2)/d*self.vel+y2)

    def _spawn(self, weapon_db):
        """
        creates a bullet in weapon database
        """
        weapon_db.add_weapon(1, self, self.target)
        
    def atdeath(self, unit_list):
        for unit in unit_list:
            if unit.target == self:
                unit.target = 0
